package com.hys.app.service.erp.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hys.app.framework.database.WebPage;
import com.hys.app.framework.util.PageConvert;
import com.hys.app.framework.util.StringUtil;
import com.hys.app.mapper.erp.StockStatisticsMapper;
import com.hys.app.model.erp.dos.ProductDO;
import com.hys.app.model.erp.dos.StockStatistics;
import com.hys.app.model.erp.dto.StockStatisticsQueryParam;
import com.hys.app.service.erp.ProductManager;
import com.hys.app.service.erp.StockStatisticsManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static com.hys.app.framework.util.CollectionUtils.convertList;
import static com.hys.app.framework.util.CollectionUtils.convertMap;

/**
 * 库存统计业务接口实现
 *
 * @author dmy
 * 2023-12-05
 */
@Service
public class StockStatisticsManagerImpl extends ServiceImpl<StockStatisticsMapper, StockStatistics> implements StockStatisticsManager {

    @Autowired
    private StockStatisticsMapper stockStatisticsMapper;

    @Autowired
    private ProductManager productManager;

    /**
     * 查询库存统计分页列表数据
     *
     * @param params 查询参数
     * @return
     */
    @Override
    public WebPage listStock(StockStatisticsQueryParam params) {
        IPage<StockStatistics> iPage = this.stockStatisticsMapper.selectStockStatisticsPage(new Page<>(params.getPageNo(), params.getPageSize()), params);
        fillData(iPage.getRecords());
        return PageConvert.convert(iPage);
    }

    /**
     * 查询库存成本统计分页列表数据
     *
     * @param params 查询参数
     * @return
     */
    @Override
    public WebPage listStockCost(StockStatisticsQueryParam params) {
        IPage<StockStatistics> iPage = this.lambdaQuery()
                .eq(params.getDeptId() != null, StockStatistics::getDeptId, params.getDeptId())
                .eq(params.getWarehouseId() != null, StockStatistics::getWarehouseId, params.getWarehouseId())
                .eq(params.getCategoryId() != null, StockStatistics::getCategoryId, params.getCategoryId())
                .like(StringUtil.notEmpty(params.getProductName()), StockStatistics::getProductName, params.getProductName())
                .like(StringUtil.notEmpty(params.getStockSn()), StockStatistics::getStockSn, params.getStockSn())
                .orderByDesc(StockStatistics::getCreateTime)
                .page(new Page<>(params.getPageNo(), params.getPageSize()));
        return PageConvert.convert(iPage);
    }

    /**
     * 根据批次ID获取库存统计信息
     *
     * @param batchId 批次ID
     * @return
     */
    @Override
    public StockStatistics getModel(Long batchId) {
        return this.lambdaQuery()
                .eq(StockStatistics::getBatchId, batchId)
                .one();
    }

    /**
     * 修改产品库存预警数量
     *
     * @param productId 产品ID
     * @param stockWarningNum 库存预警数量
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateStockWarningNum(Long productId, Integer stockWarningNum) {
        this.lambdaUpdate()
                .set(StockStatistics::getWarningNum, stockWarningNum)
                .eq(StockStatistics::getProductId, productId)
                .update();
    }

    /**
     * 导出库存统计列表数据
     *
     * @param response
     * @param params 查询参数
     */
    @Override
    public void export(HttpServletResponse response, StockStatisticsQueryParam params) {
        //查询库存统计信息
        List<StockStatistics> list = this.stockStatisticsMapper.selectStockStatisticsPage(params);
        fillData(list);

        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList();
        ExcelWriter writer = ExcelUtil.getWriter(true);
        for (StockStatistics statistics : list) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("仓库名称", statistics.getWarehouseName());
            map.put("商品编号", statistics.getProductSn());
            map.put("商品名称", statistics.getProductName());
            map.put("商品类别", statistics.getCategoryName());
            map.put("规格型号", statistics.getSpecification());
            map.put("单位", statistics.getUnit());
            map.put("入库数量", statistics.getInNum());
            map.put("供应商退货", statistics.getSupplierReturnNum());
            map.put("出库数量", statistics.getOutNum());
            map.put("订单退货", statistics.getOrderReturnNum());
            map.put("调入（出）", statistics.getTransferInNum() + "（" + statistics.getTransferOutNum() + "）");
            map.put("换货", statistics.getChangeNum());
            map.put("库存调整", statistics.getDamageNum());
            map.put("库存数量", statistics.getStockNum());
            map.put("预警数量", statistics.getWarningNum());
            rows.add(map);
        }

        writer.write(rows, true);

        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=stock_statistics.xlsx");
        writer.flush(out, true);
        writer.close();
        IoUtil.close(out);
    }

    /**
     * 导出库存成本统计列表数据
     *
     * @param response
     * @param params 查询参数
     */
    @Override
    public void exportCost(HttpServletResponse response, StockStatisticsQueryParam params) {
        //查询库存成本统计信息
        params.setGroupByWarehouseEntry(true);
        List<StockStatistics> list = this.stockStatisticsMapper.selectStockStatisticsPage(params);
        fillData(list);

        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList();
        ExcelWriter writer = ExcelUtil.getWriter(true);
        for (StockStatistics statistics : list) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("仓库名称", statistics.getWarehouseName());
            map.put("入库单号", statistics.getStockSn());
            map.put("商品编号", statistics.getProductSn());
            map.put("商品名称", statistics.getProductName());
            map.put("商品类别", statistics.getCategoryName());
            map.put("规格型号", statistics.getSpecification());
            map.put("单位", statistics.getUnit());
            map.put("入库数量", statistics.getInNum());
            map.put("供应商退货", statistics.getSupplierReturnNum());
            map.put("出库数量", statistics.getOutNum());
            map.put("订单退货", statistics.getOrderReturnNum());
            map.put("调入（出）", statistics.getTransferInNum() + "（" + statistics.getTransferOutNum() + "）");
            map.put("换货", statistics.getChangeNum());
            map.put("库存调整", statistics.getDamageNum());
            map.put("库存数量", statistics.getStockNum());
            map.put("预警数量", statistics.getWarningNum());
            rows.add(map);
        }

        writer.write(rows, true);

        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=stock_cost_statistics.xlsx");
        writer.flush(out, true);
        writer.close();
        IoUtil.close(out);
    }

    private void fillData(List<StockStatistics> list) {
        if(list.isEmpty()){
            return;
        }

        // 查询预警库存
        List<Long> productIds = convertList(list, StockStatistics::getProductId);
        List<ProductDO> productList = productManager.listByIds(productIds);
        Map<Long, Integer> productWarningValueMap = convertMap(productList, ProductDO::getId, ProductDO::getWarningValue);
        for (StockStatistics stockStatistics : list) {
            stockStatistics.setWarningNum(productWarningValueMap.getOrDefault(stockStatistics.getProductId(), 0));
        }
    }
}
